//
//  NSObject+CoreKit.swift
//  OMTCoreKitSwift
//
//  Created by 昭荣伊 on 2018/12/7.
//

import Foundation

extension NSObject {
    /// 替换self的实例方法实现，将 `originalSel` 的实现替换成 `targetSel` 的实现。
    ///
    /// - Parameters:
    ///   - originSel: 原方法
    ///   - targetSel: 目标方法
    /// - Returns: 如果替换成功返回 true；否则，false。
    @discardableResult
    public static func swizzleInstanceMethod(originSel: Selector?, targetSel: Selector?) -> Bool {
        return self.swizzleInstanceMethod(originClass: self.classForCoder(), originSel: originSel, targetClass: self.classForCoder(), targetSel: targetSel)
    }
    
    
    /// 将self的实例方法 `originalSel` 的实现，替换成 `targetClass` 的实例方法 `targetSel` 的实现。
    ///
    /// - Parameters:
    ///   - originSel: 原方法
    ///   - targetClass: 目标类
    ///   - targetSel: 目标方法
    /// - Returns: 如果替换成功返回 true；否则，false。
    @discardableResult
    public static func swizzleInstanceMethod(originSel: Selector?, targetClass: AnyClass?, targetSel: Selector?) -> Bool {
        return self.swizzleInstanceMethod(originClass: self.classForCoder(), originSel: originSel, targetClass: targetClass, targetSel: targetSel)
    }
    
    /// 替换两个类的实例方法实现，将 `originalClass` 的实例方法 `originalSel` 的实现，替换成 `targetClass` 的实例方法 `targetSel` 的实现。
    ///
    /// - Parameters:
    ///   - originClass: 原类
    ///   - originSel: 原方法
    ///   - targetClass: 目标类
    ///   - targetSel: 目标方法
    /// - Returns: 如果替换成功返回 true；否则，false。
    @discardableResult
    public static func swizzleInstanceMethod(originClass: AnyClass?, originSel: Selector?, targetClass: AnyClass?, targetSel: Selector?) -> Bool {
        if let originClass = originClass, let originSel = originSel, let targetClass = targetClass, let targetSel = targetSel {
            let originMethod = class_getInstanceMethod(originClass, originSel)
            let targetMethod = class_getInstanceMethod(targetClass, targetSel )
            let originIMP = class_getMethodImplementation(originClass, originSel)
            let targetIMP = class_getMethodImplementation(targetClass, targetSel)
            
            if let originMethod = originMethod, let targetMethod = targetMethod, let originIMP = originIMP, let targetIMP = targetIMP {
                class_addMethod(originClass, originSel, originIMP, method_getTypeEncoding(originMethod))
                class_addMethod(targetClass, targetSel, targetIMP, method_getTypeEncoding(targetMethod))
                method_exchangeImplementations(originMethod, targetMethod)
                return true
            }
        }
        return false
    }
    
    
    /// 替换self class的类方法实现，将 `originalSel` 替换成 `targetSel` 的实现。
    ///
    /// - Parameters:
    ///   - originSel: 原类方法
    ///   - targetSel: 目标类方法
    /// - Returns: 如果替换成功返回 YES；否则，NO。
    @discardableResult
    public static func swizzleClassMethod(originSel: Selector?, targetSel: Selector?) -> Bool {
        return self.swizzleClassMethod(originClass: self.classForCoder(), originSel: originSel, targetClass: self.classForCoder(), targetSel: targetSel)
    }
    
    /// 将self class的 `originalSel` 类方法实现，替换成 `targetClass` 的类方法 `targetSel` 的实现。
    ///
    /// - Parameters:
    ///   - originSel: 原类方法
    ///   - targetClass: 目标类
    ///   - targetSel: 目标类方法
    /// - Returns: 如果替换成功返回 true；否则，false。
    @discardableResult
    public static func swizzleClassMethod(originSel: Selector?, targetClass: AnyClass?, targetSel: Selector?) -> Bool {
        return self.swizzleClassMethod(originClass: self.classForCoder(), originSel: originSel, targetClass: targetClass, targetSel: targetSel)
    }
    
    /// 替换两个类的类方法实现，将 `originalClass` 的类方法 `OriginalSel`的实现，替换成 `targetClass` 的类方法 `targetSel`的实现。
    ///
    /// - Parameters:
    ///   - originClass: 原类
    ///   - originSel: 原类方法
    ///   - targetClass: 目标类
    ///   - targetSel: 目标类方法
    /// - Returns: 如果替换成功返回 true；否则，false。
    @discardableResult
    public static func swizzleClassMethod(originClass: AnyClass?, originSel: Selector?, targetClass: AnyClass?, targetSel: Selector?) -> Bool {
        if let originClass = originClass, let originSel = originSel, let targetClass = targetClass, let targetSel = targetSel {
            let originMethod = class_getClassMethod(originClass, originSel)
            let targetMethod = class_getClassMethod(targetClass, targetSel )
            
            if let originMethod = originMethod, let targetMethod = targetMethod {
                method_exchangeImplementations(originMethod, targetMethod)
                return true
            }
        }
        return false
    }
}
